﻿using System;
using System.Globalization;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Converts.Core;
using zijian666.Converts.Extensions;

using static System.Single;

namespace zijian666.Converts.Convertor;

/// <summary>
/// <seealso cref="float"/> 转换器
/// </summary>
public class SingleConvertor : FromConvertor<float>
                            , IFromConvertible<float>
                            , IFrom<byte[], float>
{
    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, bool input) => input ? 1 : 0;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, char input) => input;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, sbyte input) => input;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, byte input) => input;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, short input) => input;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, ushort input) => input;

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, int input) => input;

    /// <inheritdoc />

    public ConvertResult<float> From(IConvertContext context, uint input)
    {
        if (input > MaxValue)
        {
            return ExceptionHelper.Overflow($"{input} > {MaxValue}", context.Settings.CultureInfo);
        }
        return input;
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, long input)
    {
#pragma warning disable IDE0078 // 使用模式匹配
        if ((input < MinValue) || (input > MaxValue))
        {
            return ExceptionHelper.Overflow(input < MinValue ? $"{input} < {MinValue}" : $"{input} > {MaxValue}", context.Settings.CultureInfo);
        }
#pragma warning restore IDE0078 // 使用模式匹配
        return input;
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, ulong input)
    {
        if (input > MaxValue)
        {
            return ExceptionHelper.Overflow($"{input} > {MaxValue}", context.Settings.CultureInfo);
        }
        return input;
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, float input)
    {
        if (input is < MinValue or > MaxValue)
        {
            return ExceptionHelper.Overflow(input < MinValue ? $"{input} < {MinValue}" : $"{input} > {MaxValue}", context.Settings.CultureInfo);
        }
        return (float)input;
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, double input)
    {
        if (input is < MinValue or > MaxValue)
        {
            return ExceptionHelper.Overflow(input < MinValue ? $"{input} < {MinValue}" : $"{input} > {MaxValue}", context.Settings.CultureInfo);
        }
        return (float)input;
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, decimal input) => decimal.ToSingle(input);

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, DateTime input) => context.ConvertFail(this, input);

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, string input)
    {
        var s = input?.Trim() ?? "";
        if (TryParse(s, NumberStyles.Any, context.Settings.NumberFormatInfo ?? NumberFormatInfo.CurrentInfo, out var result))
        {
            return result;
        }
        if (s.Length > 2)
        {
            if (s[0] == '0')
            {
                switch (s[1])
                {
                    case 'x':
                    case 'X':
                        if (long.TryParse(s.Substring(2), NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out var result0))
                        {
                            return result0;
                        }
                        break;
                    case 'b':
                    case 'B':
                        try
                        {
                            return System.Convert.ToInt64(s.Substring(2), 2);
                        }
                        catch (Exception e)
                        {
                            return e;
                        }
                    default:
                        break;
                }
            }
            else if (s[0] == '&' && (s[1] == 'H' || s[1] == 'h'))
            {
                if (TryParse(s.Substring(2), NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out result))
                {
                    return result;
                }
            }
        }
        return context.ConvertFail(this, input);
    }

    /// <inheritdoc />
    public ConvertResult<float> From(IConvertContext context, byte[] input)
    {
        if (input is null || input.Length > sizeof(float))
        {
            return context.ConvertFail(this, input);
        }
        Array.Resize(ref input, sizeof(float));
        return BitConverter.ToSingle(input, 0);
    }
}